<?php
/**
 * Created by PhpStorm.
 * User: leo
 * Date: 16/4/6
 * Time: 上午9:36
 * Modify: 2016-04-06
 * Describe:
 */

namespace services\sms;

use Yii;

abstract class SmsBase extends \yii\base\Component
{


    /**
     * @var string $url 接口地址
     */
    protected $url;
    /**
     * @var resource $ch curl句柄
     */
    protected $ch = null;

    /**
     * @var int 单个curl exec次数, 每300次关闭重开一次.
     */
    public $queryTimes = 0;

    /**
     * @var Sms $sms 数据表模型
     */
    protected $sms;
    /**
     * @var int $marketing
     * 营销短信: 1
     * 非营销短信: 0
     */
    public $marketing = 0;

    protected $status = array();

    public function __construct($config = [])
    {
        parent::__construct($config);
        #get_class($this);
        $this->sms = new Sms();


    }

    function __destruct()
    {
        if ($this->ch) {
            curl_close($this->ch);
        }
    }

    public static function shortClassName()
    {
        #$className = parent::className();
        #return substr($className, strrpos($className, '\\') + 1);
        return (new \ReflectionClass(static::className()))->getShortName();
    }

    /**
     * @param string $cell 手机号
     * @param string $content 短信内容
     * @param string $sendTime 发送时间, 空为立即发送
     * @return bool 待传输数据
     */
    abstract protected function getDataStruct($cell, $content, $sendTime = '');

    /**
     * @param string $url
     * @param array $data
     * @param string $method
     * @return mixed
     */
    public function curl($url, $data = array(), $method = 'post')
    {

        $post_data = '';
        if (!empty($data)) {
            $post_data = implode('&', array_map(function ($k, $v) {
                return "$k=" . urlencode($v);
            }, array_keys($data), array_values($data)));
        }

        if (!is_null($this->ch) && $this->queryTimes % 300 == 0) {
            curl_close($this->ch);
        }

        if (!isset($this->ch) || empty($this->ch)) {
            $this->ch = curl_init();
        }

        curl_setopt($this->ch, CURLOPT_HEADER, 0);
        if (strtolower($method) == 'post') {

            curl_setopt($this->ch, CURLOPT_POST, 1);
            curl_setopt($this->ch, CURLOPT_URL, $url);
            curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post_data);
        } else {
            if (strpos('?', $url) === false) {
                $url .= '?' . $post_data;
            } else {
                $url .= '&' . $post_data;
            }
            #echo "\n", "\n", $url, "\n";
            curl_setopt($this->ch, CURLOPT_POST, 0);
            curl_setopt($this->ch, CURLOPT_URL, $url);
        }
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec($this->ch);
        $this->queryTimes++;

        return $result;
    }


    /**
     * @param array|string $cell
     * @param string $content
     * @param int $uid
     * @param int $department
     * @param string $sendTime
     * @return mixed
     * @describe 单条发送
     */
    abstract public function setSingleMsm($cell, $content, $uid = 0, $department = 12, $sendTime = '');
    public function send($cell, $content, $uid = 0, $department = 12, $sendTime = ''){
        return $this->setSingleMsm($cell, $content, $uid, $department, $sendTime);
    }


    /**
     * @param array $cell
     * @param string $content
     * @param int $uid
     * @param int $department
     * @param string $sendTime
     * @return bool
     * 发送多条内容相同的短信
     * 兼容之前代码, 手机号码 与 短信内容用||分隔.
     *
     */
    public function sendBatchMessage($cell, $content, $uid = 0, $department = 12, $sendTime = '')
    {

        /**
         * 为兼容以前代码
         * 以前$cell为分号（;）分隔,
         */
        if (is_string($cell)) {
            $cell = str_replace(';', ',', $cell);
        }
        if (is_array($cell)) {
            $cell = implode(',', $cell);
        }
        if (isset($this->preSign)) {
            $content = $this->preSign . $content;
        }
        if (isset($this->aftSign)) {
            $content .= $this->aftSign;
        }

        return $this->setSingleMsm($cell, $content, $uid, $department, $sendTime);
    }


    /**
     * @param array $cell 目标手机号，多个手机号码用||分割;
     * @param array $content 短消息内容,多个内容用||分隔;
     * @param int $uid
     * @param int $department
     * @param string $sendTime
     * @return bool
     *
     * 批量发送个性化短信
     * 号码和内容||分隔数量必须相等
     *
     * 此方法兼容旧代码, 正奥, 希奥短信皆不支持, 指发送定制短信, 使用单发方法 setSingleMsm
     */
    public function sendPersonalMessages($cell, $content, $uid = 0, $department = 12, $sendTime = '')
    {

        if (is_array($cell) && is_array($content)) {
            $arr = array_combine($cell, $content);
            foreach ($arr as $cell => $content) {
                $this->setSingleMsm($cell, $content, $uid, $department, $sendTime);
            }
        }
        return true;

    }

    /**
     * @return string
     * 取得用户IP地址
     */
    public function getClientIp()
    {
        return Yii::$app->request->userIP;
    }

    /**
     * @param string $cell
     * @param string $content
     * @return bool
     * 检查用户手机号码发送频率 ,判断用户是否可以发送难码短信
     * 默认每个手机号码每天接收 不超过20条短信
     */
    public function cellCheck($cell, $content)
    {
        $crc_code = crc32($content);
        $smsCheckDate = Yii::$app->params['smsCheckDate'];
        $cellCheckTime = Yii::$app->params['cellCheckTime'];
        $cellCheckNum = Yii::$app->params['cellCheckNum'];
        $redis = &Yii::$app->redis;

        $date = $redis->get($smsCheckDate);
        if ($date !== date('Ymd')) {
            $redis->set($smsCheckDate, date('Ymd'));
            $redis->del($cellCheckTime);
            $redis->del($cellCheckNum);

        }


        // 10秒内直接丢弃
        $time = $redis->zscore($cellCheckTime, $cell . $crc_code);
        $redis->zincrby($cellCheckTime, time() - $time, $cell . $crc_code);
        if ($time !== false && abs(time() - $time) < 10) {
            return true;
        }

        // 每个手机号每天不超过20条记录
        $r = $redis->zincrby($cellCheckNum, 1, $cell);
        if ($r > 20) {
            return true;
        }

        return false;
    }

    /**
     * @return string 上行短信内容
     *
     * 取回用户回复信息
     */
    abstract public function getReceivedMsg();

    /**
     * @return string 服务器返回消息
     * 接收用户信息(包括余额等)
     */
    abstract public function getUserInfo();

    /**
     * @param string $context 接口返回数据
     * @return mixed
     *
     * 处理返回数据
     */
    abstract protected function parseResult($context);

    /**
     * @param int $taskId 任务id
     * @param string|int $cell 手机号码
     * @param string $content 短信内容
     * @param int $uid 发送者uid
     * @param int $department 发送者部门 ,后台用户
     * @param string $sendTime 定时发送时间
     * @return mixed
     * 保存发送数据到数据库
     */
    public function saveData($taskId, $cell, $content, $uid = 0, $department = 0, $sendTime = '')
    {
        foreach (explode(',', $cell) as $_cell) {
            $this->sms->saveData($taskId, $_cell, $content, $uid, $department, $this->marketing, $sendTime, static::shortClassName());
        }
    }

    /**
     * @param string|int $taskId 返回任务ID，空时为0
     * @param string|int $cell 上行短信手机号码
     * @param string $content 上行短信内容
     * @param string $receiveTime 上行短信接收时间
     *
     * Sms类#saveReceived($task_id, $cell, $content, $received = 0, $dt = null, $company='')
     */
    public function saveReceived($taskId, $cell, $content, $receiveTime)
    {

        $this->sms->saveReceived($taskId, $cell, $content, 1, $receiveTime, static::shortClassName());
    }

    public function updateStatus($task_id, $cell, $status, $time)
    {

        $this->sms->updateStatus($task_id, $cell, $status, $time, static::shortClassName());

    }

    /**
     * 取得发送短信状态
     * @return mixed
     */
    abstract public function getSmsStatus();

    /**
     * 保存错误信息
     * @param string $desc
     * @param array $sendData
     * @param string $receiveData
     * @param string $cell
     */
    public function saveErrorMsg($desc, $sendData, $receiveData, $cell = '')
    {
        $this->sms->saveErrors($desc, json_encode($sendData), $receiveData, $cell);
    }
}
